package com.weilx959.spt.plugin.e2sp.utils.sql;

import com.weilx959.spt.plugin.e2sp.constant.ExcelToSqlConstants;
import com.weilx959.spt.plugin.e2sp.context.ConfigurationContext;
import com.weilx959.spt.plugin.e2sp.model.statement.Statement;
import net.sf.jsqlparser.expression.*;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.schema.Column;
import org.apache.commons.lang3.StringUtils;

import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Map;
import java.util.Objects;

/**
 * sql 工具类
 *
 * @author weilx
 * @since 2024-06-28
 */
public class SqlUtil {
    private SqlUtil() {}


    /**
     * 转换语句对象
     *
     * @param statement   语句对象
     * @param targetClass 目标类
     * @param <T>         目标类型
     * @return {@link T}
     */
    public static <T extends Statement> T cast(Statement statement, Class<T> targetClass) {
        if (targetClass.isAssignableFrom(statement.getClass())) {
            return targetClass.cast(statement);
        }
        return null;
    }

    /**
     * 获取值表达式
     *
     * @param value 值
     * @return {@link Expression}
     */
    public static Expression getValueExpression(Object value) {
        if (Objects.isNull(value)) {
            return new NullValue();
        }
        if (value instanceof Long l) {
            return new LongValue(l);
        }
        if (value instanceof Double d) {
            DoubleValue douleValue = new DoubleValue();
            douleValue.setValue(d);
            return douleValue;
        }
        if (value instanceof Date date) {
            return new DateValue(date);
        }
        if (value instanceof Time time) {
            TimeValue timeValue = new TimeValue();
            timeValue.setValue(time);
            return timeValue;
        }
        if (value instanceof Timestamp timestamp) {
            TimestampValue timestampValue = new TimestampValue();
            timestampValue.setValue(timestamp);
            return timestampValue;
        }
        String stringValue = value.toString();

        if (ConfigurationContext.get().isEmptyToNull() && StringUtils.isEmpty(stringValue)) {
            return new NullValue();
        }
        if (ConfigurationContext.get().isFirstDollarEscape()
            && stringValue.startsWith(ExcelToSqlConstants.RAW_FUNCTION_PREFIX)) {
            return new StringValue(stringValue);
        }
        return new StringValue(escape(stringValue));
    }

    /**
     * 转义SQL字符串
     *
     * @param value SQL字符串
     * @return {@link String}
     */
    public static String escape(String value) {
        value = value.replace("'", "''");
        value = value.replace("&", "&'||'");
        return value;
    }

    /**
     * 解析where表达式，只支持简单的等于条件
     *
     * @param expression 表达式
     * @param result 结果
     */
    public static void parseWhereExpression(Expression expression, Map<String, Object> result) {
        if (Objects.isNull(result)) {
            throw new IllegalArgumentException("result cannot be null");
        }
        if (Objects.isNull(expression)) {
            return;
        }
        if (expression instanceof AndExpression andExpression) {
            parseWhereExpression(andExpression.getLeftExpression(), result);
            parseWhereExpression(andExpression.getRightExpression(), result);
        } else if (expression instanceof EqualsTo equalsTo) {
            String key = String.valueOf(getValue(equalsTo.getLeftExpression()));
            Object value = getValue(equalsTo.getRightExpression());
            result.put(key, value);
        } else if (expression instanceof IsNullExpression isNull) {
            String key = String.valueOf(getValue(isNull.getLeftExpression()));
            result.put(key, null);
        } else {
            throw new IllegalArgumentException("unsupported expression: " + expression);
        }
    }

    /**
     * 获取值
     *
     * @param expression 表示
     * @return {@link Object }
     */
    public static Object getValue(Expression expression) {
        if (expression instanceof LongValue l) {
            return l.getValue();
        }
        if (expression instanceof DoubleValue d) {
            return d.getValue();
        }
        if (expression instanceof DateValue date) {
            return date.getValue();
        }
        if (expression instanceof TimeValue time) {
            return time.getValue();
        }
        if (expression instanceof TimestampValue timestamp) {
            return timestamp.getValue();
        }
        if (expression instanceof StringValue s) {
            return s.getValue();
        }
        if (expression instanceof NullValue) {
            return null;
        }
        if (expression instanceof Column c) {
            return c.getColumnName();
        }
        if (expression instanceof Function function) {
            if (function.getName().equalsIgnoreCase(ExcelToSqlConstants.NOW_FUNCTION)
                || function.getName().equalsIgnoreCase(ExcelToSqlConstants.SYSDATE_FUNCTION)) {
                return ExcelToSqlConstants.SYSDATE_FUNCTION;
            }
            return ExcelToSqlConstants.RAW_FUNCTION_PREFIX + function;
        }
        // 匹配不上，返回原表达式
        return expression;
    }
}
